package com.atguigu.gmall.cart.service;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.cart.feign.GmallPmsClient;
import com.atguigu.gmall.cart.feign.GmallSmsClient;
import com.atguigu.gmall.cart.feign.GmallWmsClient;
import com.atguigu.gmall.cart.interceptor.LoginInterceptor;
import com.atguigu.gmall.cart.mapper.CartMapper;
import com.atguigu.gmall.cart.pojo.Cart;
import com.atguigu.gmall.cart.pojo.UserInfo;
import com.atguigu.gmall.common.bean.ResponseVo;
import com.atguigu.gmall.common.exception.CartException;
import com.atguigu.gmall.pms.entity.SkuAttrValueEntity;
import com.atguigu.gmall.pms.entity.SkuEntity;
import com.atguigu.gmall.sms.vo.ItemSaleVo;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.checkerframework.checker.units.qual.K;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.concurrent.ListenableFuture;

import javax.swing.text.Caret;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CartService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private CartAsyncService asyncService;

    @Autowired
    private GmallPmsClient pmsClient;

    @Autowired
    private GmallWmsClient wmsClient;

    @Autowired
    private GmallSmsClient smsClient;

    private static final String KEY_PREFIX = "cart:info:";
    private static final String PRICE_PREFIX = "cart:price:";

    public void addCart(Cart cart) {// skuId count
        // 获取登录信息。如果登录了取userId 如果没有登录则取userKey
        String userId = getUserId();

        //this.redisTemplate.opsForHash()
        // 通过外层的key获取该用户的购物车 Map<skuId, cartJson>
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);

        String skuId = cart.getSkuId().toString();
        BigDecimal count = cart.getCount(); // 新增的数量
        // 判断该用户的购物车是否包含该商品
        if (hashOps.hasKey(skuId)){
            // 包含，则更新数量
            String json = hashOps.get(skuId).toString();
            cart = JSON.parseObject(json, Cart.class);
            cart.setCount(cart.getCount().add(count));
            // 保存到数据库
            this.asyncService.update(userId, skuId, cart);
        } else {
            // 不包含，则新增记录
            cart.setUserId(userId);
            cart.setCheck(true);

            // 根据skuId查询sku
            ResponseVo<SkuEntity> skuEntityResponseVo = this.pmsClient.querySkuById(cart.getSkuId());
            SkuEntity skuEntity = skuEntityResponseVo.getData();
            if (skuEntity == null) {
                throw new CartException("您要添加到购物车的商品不存在！");
            }
            cart.setTitle(skuEntity.getTitle());
            cart.setDefaultImage(skuEntity.getDefaultImage());
            cart.setPrice(skuEntity.getPrice());

            // 查询销售属性
            ResponseVo<List<SkuAttrValueEntity>> saleAttrResponseVo = this.pmsClient.querySaleAttrValuesBySkuId(cart.getSkuId());
            List<SkuAttrValueEntity> skuAttrValueEntities = saleAttrResponseVo.getData();
            cart.setSaleAttrs(JSON.toJSONString(skuAttrValueEntities));

            // 查询营销信息
            ResponseVo<List<ItemSaleVo>> salesResponseVo = this.smsClient.querySalesBySkuId(cart.getSkuId());
            List<ItemSaleVo> itemSaleVos = salesResponseVo.getData();
            cart.setSales(JSON.toJSONString(itemSaleVos));

            // 查询库存
            ResponseVo<List<WareSkuEntity>> wareResponseVo = this.wmsClient.queryWareSkusBySkuId(cart.getSkuId());
            List<WareSkuEntity> wareSkuEntities = wareResponseVo.getData();
            if (!CollectionUtils.isEmpty(wareSkuEntities)){
                cart.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity -> wareSkuEntity.getStock() - wareSkuEntity.getStockLocked() > 0));
            }

            // 新增到数据库
            this.asyncService.insert(userId, cart);
            // 新增价格缓存
            this.redisTemplate.opsForValue().set(PRICE_PREFIX + skuId, skuEntity.getPrice().toString());
        }
        hashOps.put(skuId, JSON.toJSONString(cart));

    }

    private String getUserId() {
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userId = userInfo.getUserKey();
        if (userInfo.getUserId() != null){
            userId = userInfo.getUserId().toString();
        }
        return userId;
    }

    public Cart queryCart(Long skuId) {
        // 获取登录用户的唯一标识
        String userId = this.getUserId();

        // 获取内层的map
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (!hashOps.hasKey(skuId.toString())){
            throw new CartException("该购物车记录不存在");
        }
        String json = hashOps.get(skuId.toString()).toString();
        return JSON.parseObject(json, Cart.class);
    }

    @Async
    public void execute1(){
        try {
            System.out.println("service中的execute1方法开始执行。。。");
            TimeUnit.SECONDS.sleep(4);
            int i = 1/0;
            System.out.println("service中的execute1方法结束执行。。。------------------");
        } catch (InterruptedException e) {
            //return AsyncResult.forExecutionException(e);
        }
        //return AsyncResult.forValue("hello execute1");
    }

    @Async
    public void execute2(){
        try {
            System.out.println("service中的execute2方法开始执行。。。");
            TimeUnit.SECONDS.sleep(3);
            System.out.println("service中的execute2方法结束执行。。。------------------");
        } catch (InterruptedException e) {
            //return AsyncResult.forExecutionException(e);
        }
        //return AsyncResult.forValue("hello execute2");
    }

    public List<Cart> queryCarts() {
        // 获取登录信息
        UserInfo userInfo = LoginInterceptor.getUserInfo();
        String userKey = userInfo.getUserKey();

        // 1.根据userKey查询未登录的购物车Map<skuId, cartJson>
        BoundHashOperations<String, Object, Object> unloginHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userKey);
        List<Object> unloginCartJsons = unloginHashOps.values();
        List<Cart> unloginCarts = null;
        if (!CollectionUtils.isEmpty(unloginCartJsons)){
            unloginCarts = unloginCartJsons.stream().map(cartJson -> {
                Cart cart = JSON.parseObject(cartJson.toString(), Cart.class);
                cart.setCurrentPrice(new BigDecimal(this.redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId())));
                return cart;
            }).collect(Collectors.toList());
        }

        // 2.判断登录状态，如果未登录（userId==null）则直接返回
        Long userId = userInfo.getUserId();
        if (userId == null) {
            return unloginCarts;
        }

        // 3.合并未登录的购物车，到已登录的购物车中Map<skuId, cartJson>
        BoundHashOperations<String, Object, Object> loginHashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (!CollectionUtils.isEmpty(unloginCarts)){
            unloginCarts.forEach(cart -> { // 未登录的购物车对象
                String skuId = cart.getSkuId().toString();
                if (loginHashOps.hasKey(skuId)){
                    // 如果已登录的购物车已包含该记录，则数量累加
                    BigDecimal count = cart.getCount(); // 未登录购物车 的数量
                    // 获取已登录购物车对象
                    String cartJson = loginHashOps.get(skuId).toString();
                    cart = JSON.parseObject(cartJson, Cart.class); // 已登录购物车对象
                    // 更新数量
                    cart.setCount(cart.getCount().add(count));
                    // 更新到数据库
                    this.asyncService.update(userId.toString(), skuId, cart);
                } else {
                    // 如果已登录的购物车不包含该记录，则新增一条记录
                    cart.setUserId(userId.toString());
                    this.asyncService.insert(userId.toString(), cart);
                }
                loginHashOps.put(skuId, JSON.toJSONString(cart));
            });

            // 4.清除未登录的购物车
            this.redisTemplate.delete(KEY_PREFIX + userKey);
            this.asyncService.deleteByUserId(userKey);
        }

        // 5.查询已登录的购物车并返回
        List<Object> loginCartJsons = loginHashOps.values();
        if (!CollectionUtils.isEmpty(loginCartJsons)){
            return loginCartJsons.stream().map(cartJson -> {
                Cart cart = JSON.parseObject(cartJson.toString(), Cart.class);
                cart.setCurrentPrice(new BigDecimal(this.redisTemplate.opsForValue().get(PRICE_PREFIX + cart.getSkuId())));
                return cart;
            }).collect(Collectors.toList());
        }
        return null;
    }

    public void updateNum(Cart cart) {

        // 获取登录状态
        String userId = this.getUserId();

        // Map<skuId, cartJson>
        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        if (!hashOps.hasKey(cart.getSkuId().toString())) {
            throw new CartException("当前用户没有该购物车记录！");
        }
        // 要更新的数量
        BigDecimal count = cart.getCount();
        // 获取了数据库中的购物车对象
        String cartJson = hashOps.get(cart.getSkuId().toString()).toString();
        cart = JSON.parseObject(cartJson, Cart.class);
        cart.setCount(count);

        // 保存到数据库
        hashOps.put(cart.getSkuId().toString(), JSON.toJSONString(cart));
        this.asyncService.update(userId, cart.getSkuId().toString(), cart);
    }

    public void deleteCart(Long skuId) {

        String userId = this.getUserId();

        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        hashOps.delete(skuId.toString());
        this.asyncService.deleteByUserIdAndSkuId(userId, skuId);
    }

    public List<Cart> queryCheckedCartByUserId(Long userId) {

        BoundHashOperations<String, Object, Object> hashOps = this.redisTemplate.boundHashOps(KEY_PREFIX + userId);
        List<Object> cartJsons = hashOps.values();
        if (!CollectionUtils.isEmpty(cartJsons)){
            return cartJsons.stream().map(cartJson -> JSON.parseObject(cartJson.toString(), Cart.class))
                    .filter(Cart::getCheck).collect(Collectors.toList());
        }
        return null;
    }
}
